package bma.common.langutil.core;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.AbstractSequentialList;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;

/**
 * 
 * @author guanzhong
 * @since 1.0 (imported from BMA.ESP Project)
 */
public class TransformList {

	public static <FTYPE, RTYPE> List<RTYPE> transform(List<FTYPE> fromList,
			Function<? super FTYPE, ? extends RTYPE> t) {
		return (fromList instanceof RandomAccess) ? new TransformingRandomAccessList<FTYPE, RTYPE>(
				fromList, t) : new TransformingSequentialList<FTYPE, RTYPE>(
				fromList, t);
	}

	private static class TransformingRandomAccessList<FTYPE, RTYPE> extends
			AbstractList<RTYPE> implements RandomAccess, Serializable {
		final List<FTYPE> fromList;
		final Function<? super FTYPE, ? extends RTYPE> transform;

		TransformingRandomAccessList(List<FTYPE> fromList,
				Function<? super FTYPE, ? extends RTYPE> t) {
			if (fromList == null)
				throw new NullPointerException("fromList");
			if (t == null)
				throw new NullPointerException("transform");
			this.fromList = fromList;
			this.transform = t;
		}

		@Override
		public void clear() {
			fromList.clear();
		}

		@Override
		public RTYPE get(int index) {
			return transform.apply(fromList.get(index));
		}

		@Override
		public boolean isEmpty() {
			return fromList.isEmpty();
		}

		@Override
		public RTYPE remove(int index) {
			return transform.apply(fromList.remove(index));
		}

		@Override
		public int size() {
			return fromList.size();
		}

		private static final long serialVersionUID = 0;
	}

	private static class TransformingSequentialList<FTYPE, RTYPE> extends
			AbstractSequentialList<RTYPE> implements Serializable {
		final List<FTYPE> fromList;
		final Function<? super FTYPE, ? extends RTYPE> transform;

		TransformingSequentialList(List<FTYPE> fromList,
				Function<? super FTYPE, ? extends RTYPE> t) {
			if (fromList == null)
				throw new NullPointerException("fromList");
			if (t == null)
				throw new NullPointerException("transform");
			this.fromList = fromList;
			this.transform = t;
		}

		/**
		 * The default implementation inherited is based on iteration and
		 * removal of each element which can be overkill. That's why we forward
		 * this call directly to the backing list.
		 */
		@Override
		public void clear() {
			fromList.clear();
		}

		@Override
		public int size() {
			return fromList.size();
		}

		@Override
		public ListIterator<RTYPE> listIterator(final int index) {
			final ListIterator<FTYPE> delegate = fromList.listIterator(index);
			return new ListIterator<RTYPE>() {
				@Override
				public void add(RTYPE e) {
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean hasNext() {
					return delegate.hasNext();
				}

				@Override
				public boolean hasPrevious() {
					return delegate.hasPrevious();
				}

				@Override
				public RTYPE next() {
					return transform.apply(delegate.next());
				}

				@Override
				public int nextIndex() {
					return delegate.nextIndex();
				}

				@Override
				public RTYPE previous() {
					return transform.apply(delegate.previous());
				}

				@Override
				public int previousIndex() {
					return delegate.previousIndex();
				}

				@Override
				public void remove() {
					delegate.remove();
				}

				@Override
				public void set(RTYPE e) {
					throw new UnsupportedOperationException("not supported");
				}
			};
		}

		private static final long serialVersionUID = 0;
	}
}
